package base.interactive.redis;

import base.interactive.redis.bean.RedisLock;
import base.standard.exception.NoThrow;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis cluster utils
 *
 * @description: redis集群操作类
 * @author: cyj
 * @date 2020 -10-28 14:59:26
 */
@Component
@Slf4j
public class RedisClusterUtils {

    /**
     * Redis template
     */
    @Autowired
    private RedisTemplate redisTemplate;

    //==============================Redis set=============================================

    /**
     * Set *
     *
     * @param key   key
     * @param value value
     */
    @NoThrow
    public void set(Object key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * Set *
     *
     * @param key          key
     * @param value        value
     * @param milliSeconds milli seconds
     */
    @NoThrow
    public void set(Object key, Object value, long milliSeconds) {
        if (milliSeconds > 0) {
            redisTemplate.opsForValue().set(key, value, milliSeconds, TimeUnit.MILLISECONDS);
        } else {
            set(key, value);
        }
    }

    /**
     * Get object
     *
     * @param key key
     * @return the object
     * @description:
     */
    @NoThrow
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 1.0))
    public Object get(Object key) {
        return redisTemplate.opsForValue().get(key);
    }

    //==============================Redis hash=============================================

    /**
     * Hash exist boolean
     *
     * @param key    key
     * @param mapKey map key
     * @return the boolean
     * @description:
     */
    public boolean hashExist(Object key, Object mapKey) {
        return redisTemplate.opsForHash().hasKey(key, mapKey);
    }

    /**
     * Hash set *
     *
     * @param key       key
     * @param hashKey   hash key
     * @param hashValue hash value
     */
    @NoThrow
    public void hashSet(Object key, Object hashKey, Object hashValue) {
        redisTemplate.opsForHash().put(key, hashKey, hashValue);
    }

    /**
     * Hash get object
     *
     * @param key     key
     * @param hashKey hash key
     * @return the object
     * @description:
     */
    @NoThrow
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 1.0))
    public Object hashGet(Object key, Object hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * Hash delete *
     *
     * @param key     key
     * @param hashKey hash key
     */
    @NoThrow
    public void hashDelete(Object key, Object hashKey) {
        redisTemplate.opsForHash().delete(key, hashKey);
    }

    //==============================Redis common=============================================

    /**
     * Expire *
     *
     * @param key          key
     * @param milliSeconds milli seconds
     */
    @NoThrow
    public void expire(Object key, long milliSeconds) {
        if (milliSeconds > 0) {
            redisTemplate.expire(key, milliSeconds, TimeUnit.MILLISECONDS);
        }
    }

    /**
     * Llt long
     *
     * @param key key
     * @return the long
     * @description:
     */
    public long llt(Object key) {
        return redisTemplate.getExpire(key, TimeUnit.MILLISECONDS);
    }


    /**
     * Like set
     *
     * @param pattern
     * @return the set
     * @description: 于查找所有符合给定模式 pattern 的 key
     */
    public Set<Object> like(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * Recover object
     *
     * @param e e
     * @return the object
     * @description:
     */
    @Recover
    public Object recover(Exception e) {
        log.info("redis get retry failed!");
        return null;
    }

    /**
     * Try lock boolean
     *
     * @param redisLock redis lock
     * @return the boolean
     * @description:
     */
    public boolean tryLock(RedisLock redisLock) {
        return redisTemplate.opsForValue().setIfAbsent(redisLock.getKey(), redisLock.getValue(), redisLock.getExpire(),
                redisLock.getTimeUnit());
    }


    /**
     * Un lock *
     *
     * @param redisLock redis lock
     */
    public void unLock(RedisLock redisLock) {
        this.delete(redisLock.getKey());
    }

    /**
     * Delete *
     *
     * @param key key
     */
    @NoThrow
    public void delete(Object key) {
        redisTemplate.delete(key);
    }

    @NoThrow
    public void deletes(Set<Object> keys) {
        redisTemplate.delete(keys);
    }
}
